package ch.six4rty.doodle
{
	/**
	 * Doodle Singleton
	 * 
	 *  @author Tiago Dias [six4rty.ch, Switzerland]
	 */	
	
	import ch.six4rty.doodle.data.PollData;
	import ch.six4rty.doodle.data.PollDataBuilderVO;
	import ch.six4rty.doodle.events.DoodleEvent;
	import ch.six4rty.doodle.events.OAuthEvent;
	import ch.six4rty.doodle.oauth.OAuthHelper;
	import ch.six4rty.doodle.utils.XMLConstructor;
	
	import com.adobe.net.URI;
	
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.utils.ByteArray;
	
	import nl.demonsters.debugger.MonsterDebugger;
	
	import org.flaircode.oauth.IOAuth;
	import org.flaircode.oauth.OAuth;
	import org.httpclient.HttpClient;
	import org.httpclient.events.HttpDataEvent;
	import org.httpclient.events.HttpListener;
	import org.httpclient.events.HttpResponseEvent;
	import org.httpclient.events.HttpStatusEvent;
	import org.httpclient.http.Post;
	import org.httpclient.http.Put;
	import org.iotashan.oauth.OAuthRequest;
	import org.iotashan.oauth.OAuthToken;
	import org.osmf.utils.URL;
	
	public class Doodle extends EventDispatcher
	{
		private static var _instance			:Doodle;
		
		public static const _PRODUCTION			:String = "http://doodle.com/api1";
		public static const _TESTING			:String = "http://doodle-test.com/api1WithoutAccessControl";
		
		private var _oauthKey			:String 			= "mwuzuih16jxgyiwyndyo88mug28mvypd";
		private var _oauthSecret		:String 			= "kyqmhtxzb6ctea6pdak3a7yeas87pygy";
		
		private static var _requestToken		:OAuthToken;
		private static var _accessToken			:OAuthToken;
		private static var _doodleID			:String;
		private static var _doodleServer		:String;
		
		private var _oauthHelper				:OAuthHelper;
		private var _oauth						:IOAuth;
		private var _pollData					:PollData;
		private var _xmlData					:XML;
		
		private var _xml						:XML;
		private var _xmlReq						:URLRequest;
		private var _xmlBA						:ByteArray;
		private var _uri						:URI;
		
		public static function getInstance():Doodle
		{
			if( _instance == null )
			
				_instance = new Doodle();
				return _instance;	
			
		}
		
		public function init():void
		{
			_oauthHelper = new OAuthHelper( _oauthKey, _oauthSecret );
			_oauthHelper.addEventListener( OAuthEvent.ACCESSTOKEN_RECEIVED, setupOAuth );
			
		}
		
		private function setupOAuth( e:OAuthEvent ):void
		{
			_oauth			= _oauthHelper.oauth;
			requestToken 	= _oauthHelper.requestToken;
			accessToken 	= _oauthHelper.accessToken;
			
			dispatchEvent( new DoodleEvent( DoodleEvent.DOODLE_INITIATED ) );
		}
		
		/**
		 * Request Polldata in an XML format -  - TESTED
		 * 
		 * 
		 * 
		 */	
		
		//-----------------------------------------------
		//GET METHODS
		public function requestByID():void
		{
			_xmlReq = _oauth.buildRequest( "GET", serverType + "/polls/" + doodleID, accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri = new URI( _xmlReq.url );
			clientHandler( _uri, "get" );
		}
		
		/**
		 * 
		 * @param doodleID
		 * 
		 */		
		
		//-----------------------------------------------
		//PUT METHODS
		
		public function putPoll( pd:PollDataBuilderVO ):void
		{
			_xml		= XMLConstructor.poll( pd );	
			
			_xmlBA = new ByteArray();
			_xmlBA.writeUTFBytes( _xml );
			_xmlBA.position = 0;	
			
			_xmlReq = _oauthHelper.oauth.buildRequest( "POST", serverType + "/polls", accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri		= new URI( _xmlReq.url );
			
			clientHandler( _uri, "post", _xmlBA );
		}
		
		/**
		 * 
		 * A simplified function that handles the whole communication with the doodle API
		 * 
		 * 
		 * @param uri
		 * @param action
		 * 
		 */		
		private function clientHandler( uri:URI, action:String, data:ByteArray = null ):void
		{
			if ( client )
			{
				client.listener = null;
				client 			= null;	
			}
			
			var client:HttpClient			= new HttpClient();
			client.listener.onData			= function( evt:HttpDataEvent ):void
			{
				MonsterDebugger.trace(this, "DATA EVENT" );
				var data:ByteArray = evt.bytes; 
				handleResults( data );
			}
			client.listener.onComplete		= function ( evt:HttpResponseEvent ):void
			{
				MonsterDebugger.trace(this, "COMPLETE EVENT" );
				MonsterDebugger.trace(this, evt );	
			}
			
			client.listener.onStatus		= function( evt:HttpStatusEvent ):void
			{
				MonsterDebugger.trace(this, "STATUS EVENT" );
				MonsterDebugger.trace(this, evt );
			}
				
			
				
			switch( action )
			{
				case "get":
					client.get( uri );
					break;
				case "post":
					client.post( uri, data, "application/xml" );
					break;
				case "put":
					client.put( uri, data, "application/xml" );
					break;
				case "delete":
					client.del( uri );
					break;
				default:
					throw new Error( "INVALID ARGUMENT, you are only allowed to use GET, POST, PUT and DELETE" );
			}
			
		}
		
		private function handleResults( ba:ByteArray ):void
		{
			_xmlData 			= new XML( ba.toString() );		
			_pollData			= new PollData( _xmlData );
			
			MonsterDebugger.trace(this, _pollData );
		}
		
		
		//-----------------------------------------------
		//DELETE METHODS
		
		/**
		 * Delete Comment - TESTED
		 * 
		 * @param id1 denotes the poll’s 16-character identifier.
		 * @param id2 denotes the participant’s identifier.
		 * 
		 */		
		public function deleteComment( id1:String ):void
		{
			_xmlReq = _oauth.buildRequest( "DELETE", serverType + "/polls/" + doodleID + "/comments/" + id1, accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri = new URI( _xmlReq.url );
			clientHandler( _uri, "delete" );
		}
		
		/**
		 * Delete Participant - TESTED
		 * 
		 * @param id1 denotes the poll’s 16-character identifier.
		 * @param id2 denotes the participant’s identifier.
		 * 
		 */	
		public function deleteParticipant( id1:String ):void
		{
			_xmlReq = _oauth.buildRequest( "DELETE", serverType + "/polls/" + doodleID + "/participants/" + id1, accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri = new URI( _xmlReq.url );
			clientHandler( _uri, "delete" );
		}
		
		
		//-----------------------------------------------
		//POST METHODS
		
		/**
		 * Post new Comment - TESTED
		 * 
		 * @param doodleID
		 * 
		 */		
		public function postComment( pName:String, pComment:String ):void
		{
			_xml = XMLConstructor.comment(pName, pComment);
			
			_xmlBA = new ByteArray();
			_xmlBA.writeUTFBytes( _xml );
			_xmlBA.position = 0;
			
			_xmlReq = _oauth.buildRequest( "POST", serverType + "/polls/" + doodleID + "/comments", accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri = new URI( _xmlReq.url );
			
			clientHandler( _uri, "post", _xmlBA );
		}
		
		/**
		 * Post a new participant (entry) into the designated Poll - TESTED(static) needs to be tested dynamically
		 * 
		 * @param doodleID
		 * 
		 */		
		public function postParticipant( pName:String, options:Array):void
		{
			_xml = XMLConstructor.participant( pName, options );
			
			_xmlBA = new ByteArray();
			_xmlBA.writeUTFBytes( _xml );
			_xmlBA.position = 0;
			
			_xmlReq = _oauth.buildRequest( "POST", serverType + "/polls/" + doodleID + "/participants", accessToken );
			MonsterDebugger.trace(this, _xmlReq.url );
			
			_uri = new URI( _xmlReq.url );
			
			clientHandler( _uri, "post", _xmlBA );
		}
		
		//-----------------------------------------------
		//PUBLIC GETTERS & SETTERS
		//
		//-----------------------------------------------
		
		public function set requestToken( value:OAuthToken):void
		{
			_requestToken = value;
		}
		
		public function get requestToken():OAuthToken
		{
			return _requestToken;
		}
		
		public function set accessToken ( value:OAuthToken ):void
		{
			_accessToken = value;
		}
		
		public function get accessToken():OAuthToken
		{
			return _accessToken;
		}
		
		public function set doodleID( value:String ):void
		{
			_doodleID = value;
		}
		
		public function get doodleID():String
		{
			if ( _doodleID )
			{
				return _doodleID;
			}
			else
			{
				throw new Error("NO DOODLE ID PROVIDED");
			}
			
		}
		
		public function set serverType( value:String ):void
		{
			( value == "production" ) ? _doodleServer = _PRODUCTION : _doodleServer = _TESTING;
		}
		
		public function get serverType():String
		{
			if ( _doodleServer )
			{
				return _doodleServer;
			}
			else
			{
				throw new Error("NO DOODLE SERVER DEFINED");
			}
		}
		
	}
}